package org.daochong.lang;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.daochong.lang.ucm.Configuration;

import bsh.EvalError;
import bsh.Interpreter;

public class BshExpression extends AbstractExpression {

	public Object eval(String expression, Object obj) {
		try {
			Interpreter it = new Interpreter();
			if (obj != null) {
				expression = parse("#([^#]+)#", expression, obj, it);
				expression = parse("@([^@]+)@", expression, obj, it);
				expression = parse("\\$\\{([^\\}]+)\\}", expression, obj, it);
			}
			return it.eval(expression);
		} catch (EvalError e) {
			throw new RuntimeException("BSH-Expression Fail" + e);
		}
	}

	private String parse(String regex, String str, Object obj, Interpreter it) {
		Pattern p = Pattern.compile(regex);
		Matcher matcher = p.matcher(str);
		StringBuffer sb = new StringBuffer();
		boolean result = matcher.find();
		while (result) {
			String key = matcher.group();
			Object o = BeanUtil.getValue(obj, key);
			if (key.startsWith("${")) {
				key = "EL_" + BeanUtil.toBeanString(key.substring(2, key.length() - 1));
			} else if ((key.startsWith("#") && key.endsWith("#")) || (key.startsWith("@") && key.endsWith("@"))) {
				key = "P_" + BeanUtil.toBeanString(key.substring(1, key.length() - 1));
			}
			key = key.replaceAll("\\[", "").replaceAll("\\]", "");
			try {
				it.set(key, o);
			} catch (Throwable e) {
				throw new RuntimeException("Expression Fail", e);
			}
			matcher.appendReplacement(sb, key);
			result = matcher.find();
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	public static void main(String[] args) throws Exception {
		AbstractContext context = new AbstractContext();
		context.setAttribute("id", "ABC");
		context.setParameter("id", "ABC");
		Configuration cfg = new Configuration();
		cfg.setConfigId("user");
		cfg.setGroupId("default");
		context.setAttribute("config", cfg);
		context.setParameter("config", cfg);

		Configuration cfg1 = new Configuration();
		cfg1.setConfigId("app");
		cfg1.setGroupId("default");
		List<Configuration> list = new ArrayList<Configuration>(1);
		list.add(cfg);
		list.add(cfg1);
		context.setAttribute("configList", list);
		context.setParameter("configList", list);
		Configuration[] ar = new Configuration[] { cfg, cfg1 };
		context.setAttribute("ar", ar);
		context.setParameter("ar", ar);

		BshExpression be = new BshExpression();
		System.out.println(be.eval("new Exception(\"A\")"));
		System.out.println(be.eval("(${config.configId}.length()>2 && 1==0)", context));
		System.out.println(be.eval("(#config.configId#.length()>2 && 1==1)", context));
		System.out.println(be.eval("${ar[1].configId}", context));
		System.out.println(be.eval("new java.util.ArrayList()"));
	}
}